/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package gfs;

import gfs.location.Coordinate;
import gfs.location.Location;
import gfs.board.Board;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 *
 * @author Joel
 */
public class StrategoSoldier implements Comparable
    {    
    
    public enum Type {SOLDIER, BOMB, FLAG};
    protected int pieceVal;
    protected String name;
    protected Type type;
    protected Location loc;
    protected Color col;
    protected int numBattles;
    protected Board board;
    
    public StrategoSoldier(String name, Type tag, Coordinate cd, 
            Color cl, Board bd)
        {
        this(99, name, tag, null, cl, bd);
        }
    
    public StrategoSoldier(int pV, String name, Type tag, Location loc,
            Color cl, Board bd)
        {
        pieceVal = pV;
        this.name = name;
        this.loc = loc;
        this.col = cl;
        board = bd;        
        setColor(cl);
        type = tag;
        numBattles = 0;
        }
    
    /**
     * Sets this soldier to a different color.
     * 
     * @param colo
     *          The new color to which this soldier is being set to.
     */
    public void setColor(Color colo)
        {
        if (col == null && colo == null)
            {
            col = Color.BLACK;
            return;
            }
        if (colo != null)
            col = colo;
        }
    
    /**
     * Compares this <code>StrategoSoldier</code> to another 
     * <code>StrategoSoldier</code>
     * @param o 
     *      The soldier object to compare this soldier to
     * @return
     *      1 if this soldier is greater than the opposing soldier. 0 if this 
     * soldier is equal to the opposing soldier. -1 if this soldier is less than
     * the opposing soldier.
     */
    public int compareTo(Object o) 
        {
        int comp = -1;
        StrategoSoldier soldier = (StrategoSoldier)o;
        if(type == Type.SOLDIER)
            {
            if(soldier.getType() == Type.BOMB)
                if(!(this instanceof StrategoMiner))
                    comp = -1;
                else
                    comp = 1;
            else
                {
                if(!(this instanceof StrategoSpy))
                    {
                    if(getVal() < soldier.getVal())
                        comp = 1;
                    if(getVal() > soldier.getVal())
                        comp = -1;
                    if(soldier.getVal() == getVal())
                        comp = 0;
                    }
                else
                    if(soldier instanceof StrategoMarshal)
                        comp = 1;
                    else if(soldier instanceof StrategoSpy)
                        comp = 0;
                        else
                            comp = -1;
                }
            }
        if(type == Type.BOMB)
            if(soldier instanceof StrategoMiner)
                comp = -1;
            else
                comp = 1;
        return comp;
        }

    /**
     * The move locations for the piece at the specified location
     *
     * @param loc
     * @return
     */
    public ArrayList<Location> getMoveLocations()
        {
        if(!board.isValid(loc))
            return null;
        ArrayList<Location> lcs = new ArrayList<Location>();
        Location north = null, south = null, west = null, east = null;
        if(loc.getRow() > 0)
            {
            north = loc.getLocFromHash(loc.hashCode() - 10);
            lcs.add(north);
            }
        if(loc.getRow() < 9)
            {
            south = loc.getLocFromHash(loc.hashCode() + 10);
            lcs.add(south);
            }
        if(loc.getCol() > 0)
            {
            west = loc.getLocFromHash(loc.hashCode() - 1);
            lcs.add(west);
            }
        if(loc.getCol() < 9)
            {
            east = loc.getLocFromHash(loc.hashCode() + 1);
            lcs.add(east);
            }
        if(lcs.isEmpty())
            lcs = null;
        return lcs;
        }

    private Type getType() 
        {
        return type;
        }

    public Location getLoc() 
        {
        return loc;
        }

    public Color getCol() 
        {
        return col;
        }

    public int getVal() 
        {
        return pieceVal;
        }

    public String getName() 
        {
        return name;
        }

    @Override
    public String toString() 
        {
        return getClass().getSimpleName() + " " + getLoc().toString().substring(9);
        }
    
    public static final Comparator getComparator()
        {
        return new Cmp();
        }
    
    public static void unitTest1()
        {
        Color blk = Color.BLACK;
        Board bd = new StrategoBoard();
        StrategoSoldier sold1 = new StrategoSpy(new Location(0,0,10), blk, bd);
        StrategoSoldier sold2 = new StrategoSpy(new Location(0,1,10), blk, bd);
        StrategoSoldier sold3 = new StrategoSpy(new Location(0,2,10), blk, bd);
        StrategoSoldier sold4 = new StrategoSpy(new Location(0,3,10), blk, bd);
        List<StrategoSoldier> list = new ArrayList<StrategoSoldier>();
        list.add(sold4);
        list.add(sold3);
        list.add(sold2);
        list.add(sold1);
        Collections.sort(list, StrategoSoldier.getComparator());
        System.out.println(list);
        }
    
    }

class Cmp implements Comparator
    {
    public int compare(Object o1, Object o2) 
        {
        StrategoSoldier ss1 = (StrategoSoldier)o1, ss2 = (StrategoSoldier)o2;
        int cmp = ss1.getLoc().hashCode() - ss2.getLoc().hashCode();
        return cmp;
        }    
    }

class StrategoMarshal extends StrategoSoldier
    {
    public StrategoMarshal(Location loc, Color cl, Board bd)
        {
        super(1, "  Marshal", Type.SOLDIER, loc, cl, bd);
        }    
    }

class StrategoGeneral extends StrategoSoldier
    {
    public StrategoGeneral(Location loc, Color cl, Board bd)
        {
        super(2, "  General", Type.SOLDIER, loc, cl, bd);
        }      
    }

class StrategoColonel extends StrategoSoldier
    {
    public StrategoColonel(Location loc, Color cl, Board bd)
        {
        super(3, "  Colonel", Type.SOLDIER, loc, cl, bd);
        }
    }

class StrategoMajor extends StrategoSoldier
    {
    public StrategoMajor(Location loc, Color cl, Board bd)
        {
        super(4, "     Major", Type.SOLDIER, loc, cl, bd);
        }
    }

class StrategoCaptain extends StrategoSoldier
    {
    public StrategoCaptain(Location loc, Color cl, Board bd)
        {
        super(5, "  Captain", Type.SOLDIER, loc, cl, bd);
        }
    }

class StrategoLieutenant extends StrategoSoldier
    {
    public StrategoLieutenant(Location loc, Color cl, Board bd)
        {
        super(6, "Lieutenant", Type.SOLDIER, loc, cl, bd);
        }
    }

class StrategoSergeant extends StrategoSoldier
    {
    public StrategoSergeant(Location loc, Color cl, Board bd)
        {
        super(7, " Sergeant", Type.SOLDIER, loc, cl, bd);
        }
    }

class StrategoScout extends StrategoSoldier
    {
    public StrategoScout(Location loc, Color cl, Board bd)
        {
        super(9, "   Scout", Type.SOLDIER, loc, cl, bd);
        }   
    
    //@Override
    public ArrayList<Coordinate> getMoveCoordinates(ArrayList<StrategoSoldier>
            network, ArrayList<StrategoSoldier> local)
        {
        ArrayList<Coordinate> coors = new ArrayList<Coordinate>();
        if (getCoordinatesUntil(loc, network, local, 0) != null)
            for (Coordinate move : getCoordinatesUntil(this.getLoc(), network,
                    local, 0))
                coors.add(move);
        if (getCoordinatesUntil(loc, network, local, 1) != null)
            for (Coordinate move : getCoordinatesUntil(this.getLoc(), network,
                    local, 1))
                coors.add(move);
        if (getCoordinatesUntil(loc, network, local, 2) != null)
            for (Coordinate move : getCoordinatesUntil(this.getLoc(), network,
                    local, 2))
                coors.add(move);
        if (getCoordinatesUntil(loc, network, local, 3) != null)
            for (Coordinate move : getCoordinatesUntil(this.getLoc(), network,
                    local, 3))
                coors.add(move);
        return coors;
        }
    
    private ArrayList<Coordinate> getCoordinatesUntil(Location init,
            ArrayList<StrategoSoldier> network, ArrayList<StrategoSoldier> local,
            int direction)
            // 0 for north, 1 for south, 2 for east, 3 for west
        {
        ArrayList<Coordinate> ret = new ArrayList<Coordinate>();
        int sameRow = 0;
        switch(direction)
            {
            case 0:
                init = init.getLocFromHash(init.hashCode() - 10);
                while (!isThere(init, network, local))
                    {
                    ret.add(init);
                    init = init.getLocFromHash(init.hashCode() - 10);
                    }
                ret.add(init);
                return ret;
            case 1:
                init = init.getLocFromHash(init.hashCode() + 10);
                while (!isThere(init, network, local))
                    {
                    ret.add(init);
                    init = init.getLocFromHash(init.hashCode() + 10);
                    }
                ret.add(init);
                return ret;
            case 2:
                sameRow = init.hashCode() / 10;
                init = init.getLocFromHash(init.hashCode() + 1);
                while (!isThere(init, network, local) && init.hashCode()
                        /10 == sameRow)
                    {
                    ret.add(init);
                    init = init.getLocFromHash(init.hashCode() + 1);
                    }
                ret.add(init);
                return ret;
            case 3:
                sameRow = init.hashCode()/10;
                init = init.getLocFromHash(init.hashCode() - 1);
                while (!isThere(init, network, local) && init.hashCode()/10 ==
                        sameRow)
                    {
                    ret.add(init);
                    init = init.getLocFromHash(init.hashCode() - 1);
                    }
                ret.add(init);
                return ret;
            default:
                return null;
            }
        }
    
    private boolean isThere(Location there, ArrayList<StrategoSoldier> network,
            ArrayList<StrategoSoldier> local)
        {
        if (there == null)
            return true;
        for (StrategoSoldier ss: network)
            if (ss.getLoc().equals(there))
                return true;
        for (StrategoSoldier ss: local)
            if (ss.getLoc().equals(there))
                return true;
        if (there.getLocFromHash(41).equals(loc))
            return true;
        if (there.getLocFromHash(42).equals(loc))
            return true;
        if (there.getLocFromHash(51).equals(loc))
            return true;
        if (there.getLocFromHash(52).equals(loc))
            return true;
        if (there.getLocFromHash(47).equals(loc))
            return true;
        if (there.getLocFromHash(48).equals(loc))
            return true;
        if (there.getLocFromHash(57).equals(loc))
            return true;
        if (there.getLocFromHash(58).equals(loc))
            return true;
        return false;
        }
    }

class StrategoMiner extends StrategoSoldier
    {
    public StrategoMiner(Location loc, Color cl, Board bd)
        {
        super(9, "   Miner", Type.SOLDIER, loc, cl, bd);
        }
    }

class StrategoSpy extends StrategoSoldier
    {
    public StrategoSpy(Location loc, Color cl, Board bd)
        {
        super(10, "    Spy", Type.SOLDIER, loc, cl, bd);
        }
    }

class StrategoFlag extends StrategoSoldier
    {
    public StrategoFlag(Location loc, Color cl, Board bd)
        {
        super("    Flag", Type.FLAG, loc, cl, bd);
        }
    }

class StrategoBomb extends StrategoSoldier
    {
    public StrategoBomb(Location loc, Color cl, Board bd)
        {
        super("     Bomb", Type.BOMB, loc, cl, bd);
        }
    }
